import { ConflictException, ForbiddenException, Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository, In, DeleteResult } from 'typeorm'
import { ConfigEntity } from '../entities/config.entity'

@Injectable()
export class ConfigService {
  constructor(
    @InjectRepository(ConfigEntity)
    private configRepository: Repository<ConfigEntity>,
  ) {}

  /**
   * 获取所有配置（分页）
   * @param page 页码，默认为1
   * @param limit 每页数量，默认为10
   */
  async findAll(page: number = 1, limit: number = 10): Promise<{ data: ConfigEntity[]; total: number }> {
    const [data, total] = await this.configRepository.findAndCount({
      skip: (page - 1) * limit,
      take: limit,
    })
    return { data, total }
  }

  /**
   * 根据键获取配置
   */
  async findByKey(key: string): Promise<ConfigEntity> {
    const config = await this.configRepository.findOneBy({ key })
    if (!config) {
      throw new NotFoundException(`配置键 ${key} 不存在`)
    }
    return config
  }

  /**
   * 删除配置
   */
  async remove(id: number): Promise<DeleteResult> {
    // 检查是否为系统配置
    const config = await this.configRepository.findOneBy({ id })
    if (!config) {
      throw new NotFoundException(`配置 ID ${id} 不存在`)
    }
    if (config.system) {
      throw new ForbiddenException(`系统配置不能删除`)
    }
    return await this.configRepository.delete(id)
  }

  /**
   * 批量获取配置
   */
  async findByKeys(keys: string[]): Promise<Record<string, any>> {
    const configs = await this.configRepository.findBy({
      key: In(keys),
    })

    return configs.reduce(
      (acc, config) => {
        try {
          // 尝试将字符串值解析为JSON
          acc[config.key] = JSON.parse(config.value) as unknown
        } catch (e) {
          // 如果解析失败，则使用原始字符串
          acc[config.key] = config.value
        }
        return acc
      },
      {} as Record<string, any>,
    )
  }

  /**
   * 创建配置
   * @throws ConflictException 如果配置键已存在
   */
  async create(key: string, value: any, options?: Partial<ConfigEntity>): Promise<ConfigEntity> {
    const existingConfig = await this.configRepository.findOneBy({ key })
    if (existingConfig) {
      throw new ConflictException(`配置键 ${key} 已存在，请更换一个配置键`)
    }

    // 将值转换为字符串
    const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value)

    const config = this.configRepository.create({
      key,
      value: valueStr,
      ...options,
    })
    return await this.configRepository.save(config)
  }

  /**
   * 更新配置
   * @throws NotFoundException 如果配置不存在
   */
  async update(key: string, value: any, options?: Partial<ConfigEntity>): Promise<ConfigEntity> {
    const config = await this.configRepository.findOneBy({ key })
    if (!config) {
      throw new NotFoundException(`配置键 ${key} 不存在`)
    }

    // 将值转换为字符串
    const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value)

    config.value = valueStr
    if (options) {
      Object.assign(config, options)
    }
    return await this.configRepository.save(config)
  }

  /**
   * 根据键获取配置值
   * @param key 配置键
   * @param defaultValue 默认值，当配置不存在时返回
   * @returns 配置值（自动解析JSON）
   */
  async getConfig<T>(key: string, defaultValue?: T): Promise<T> {
    try {
      const config = await this.findByKey(key)
      // 尝试解析JSON
      try {
        return JSON.parse(config.value) as T
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
      } catch (e) {
        return config.value as T
      }
    } catch (e) {
      // 如果配置不存在且提供了默认值，则返回默认值
      if (defaultValue !== undefined) {
        return defaultValue
      }
      throw e
    }
  }
}
